package cgl.sensorgrid.sopac.gps.filters;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;

import cgl.sensorgrid.common.PropertyFile;
import cgl.sensorgrid.filters.Filter;
import cgl.sensorgrid.sopac.gps.threadpool.ThreadPool;
import cgl.sensorgrid.sopac.gps.filters.UtilSet;

import cgl.hpsearch.common.Sys;

import cgl.narada.event.NBEvent;

import cgl.granules.exception.MarshallingException;
import cgl.granules.operation.MapReduceException;
import cgl.granules.results.ResultPayload;
import cgl.granules.results.Results;
import cgl.granules.results.ResultsFactory;

/***
 * 
 * This class extends the Filter class. It gets data from the AP data topic
 * on NaradaBrokering which contains bothe ASCII and POS data tuples. The
 * two types of data are then separated and processed.
 * 
 * Code from class RealtimeRdahmmRunner in this package.
 * 
 * @author Chao Sun
 *
 */
public class AsciiPosRdahmmRunner extends Filter {

	protected class AsciiRdahmmProcessor {

		private String siteName;
		private String modelFilePrefix;
		private String siteModelDir;
		private FileWriter fwModel;

		public AsciiRdahmmProcessor(String siteName, String modelParentDir,
				String evalParentDir, String histParentDir) {
			this.siteName = siteName;
			modelFilePrefix = siteName + "_model_ASCII";
			fwModel = null;
			siteModelDir = modelParentDir + File.separator + siteName
					+ File.separator;

			File fDir = new File(siteModelDir);
			if (!fDir.exists())
				fDir.mkdirs();
		}

		public void addLine(String line) {
			try {
				if (fwModel == null) {
					fwModel = new FileWriter(siteModelDir + modelFilePrefix
							+ ".xyz", false);
				}

				fwModel.write(line);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	protected class PosRdahmmProcessor {

		private String siteName;
		private String modelFilePrefix;
		private long lastRemodelTimeMilli;
		private long modelInputStartMilli;
		private long lastEvalTimeMilli;
		private boolean isModelBuilt;
		private String siteModelDir;
		private String siteEvalDir;
		private String siteHistDir;
		private FileWriter fwModel;
		private FileWriter fwEval;
		private FileWriter fwHist;
		private Calendar calLastHistData;
		private boolean lastModelUsableValue;
		private LinkedList stateChangeTimes;

		public PosRdahmmProcessor(String siteName, String modelParentDir,
				String evalParentDir, String histParentDir) {
			this.siteName = siteName;
			modelFilePrefix = siteName + "_model_POS";
			fwModel = null;
			fwEval = null;
			fwHist = null;
			calLastHistData = null;
			lastRemodelTimeMilli = 0;
			lastEvalTimeMilli = 0;
			siteModelDir = modelParentDir + File.separator + siteName
					+ File.separator;
			siteEvalDir = evalParentDir + File.separator + siteName
					+ File.separator;
			siteHistDir = histParentDir + File.separator + siteName
					+ File.separator;
			stateChangeTimes = new LinkedList();

			File fDir = new File(siteModelDir);
			if (!fDir.exists())
				fDir.mkdirs();
			fDir = new File(siteEvalDir);
			if (!fDir.exists())
				fDir.mkdirs();
			fDir = new File(siteHistDir);
			if (!fDir.exists())
				fDir.mkdirs();

			checkModelExists();
			lastModelUsableValue = false;
		}

		public String getSiteName() {
			return siteName;
		}

		public void setSiteName(String siteName) {
			this.siteName = siteName;
		}

		public boolean isModelBuilt() {
			return isModelBuilt;
		}

		public void setModelBuilt(boolean isModelBuilt) {
			this.isModelBuilt = isModelBuilt;
		}

		public long getLastRemodelTimeMilli() {
			return lastRemodelTimeMilli;
		}

		public void setLastRemodelTimeMilli(long lastRemodelTimeMilli) {
			this.lastRemodelTimeMilli = lastRemodelTimeMilli;
		}

		public long getLastEvalTimeMilli() {
			return lastEvalTimeMilli;
		}

		public void setLastEvalTimeMilli(long lastEvalTimeMilli) {
			this.lastEvalTimeMilli = lastEvalTimeMilli;
		}

		public void checkModelExists() {
			File fModel = new File(siteModelDir + modelFilePrefix + ".Q");
			isModelBuilt = fModel.exists();
			if (isModelBuilt) {
				lastRemodelTimeMilli = fModel.lastModified();
				if (remodelPeriodMilli > 0
						&& System.currentTimeMillis() - lastRemodelTimeMilli >= remodelPeriodMilli) {
					isModelBuilt = false;
				}
			}
		}

		public void addLine(String line) {
			if (isHistSaved)
				addHistData(line);
			if (!isModelBuilt) {
				try {
					if (fwModel == null) {
						fwModel = new FileWriter(siteModelDir + modelFilePrefix
								+ ".xyz", false);
						modelInputStartMilli = System.currentTimeMillis();
					}

					fwModel.write(line);
					if (System.currentTimeMillis() - modelInputStartMilli >= modelDataTimeMilli) {
						fwModel.flush();
						fwModel.close();
						buildModel();
						fwModel = null;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			boolean modelUsable = isModelBuilt;
			if (!modelUsable) {
				File fModel = new File(siteModelDir + modelFilePrefix + ".Q");
				if (fModel.exists()) {
					long timeSinceLastModel = System.currentTimeMillis()
							- fModel.lastModified();
					modelUsable = timeSinceLastModel < (remodelPeriodMilli
							+ modelDataTimeMilli + evalPeriodMilli);
					if (modelUsable && modelUsable != lastModelUsableValue)
						log("old model usable for site" + siteName);
				}
			}
			lastModelUsableValue = modelUsable;
			if (modelUsable) {
				try {
					if (fwEval == null) {
						fwEval = new FileWriter(
								siteEvalDir + siteName + ".xyz", false);
						lastEvalTimeMilli = System.currentTimeMillis();
					}
					fwEval.write(line);
					if (System.currentTimeMillis() - lastEvalTimeMilli >= evalPeriodMilli) {
						fwEval.flush();
						fwEval.close();
						evaluate();
						fwEval = null;
						if (remodelPeriodMilli > 0
								&& System.currentTimeMillis()
										- lastRemodelTimeMilli >= remodelPeriodMilli) {
							isModelBuilt = false;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		protected void buildModel() {
			modelThread mt = new modelThread(rdahmmTrainShellPath, siteModelDir
					+ modelFilePrefix + ".xyz", modelThreadPool);
			mt.start();
			lastRemodelTimeMilli = System.currentTimeMillis();
			isModelBuilt = true;
		}

		protected void evaluate() {
			String input = siteEvalDir + siteName + ".xyz";
			String command = rdahmmEvalShellPath + " " + input + " 5 "
					+ modelFilePrefix + " " + siteModelDir;
			String out = exec(command);
			if (out.length() > 0) {
				log("Results for RDAHMM evaluation for " + siteName + ":" + out);
			} else {
				log("Sucessfully done RDAHMM evaluation for " + siteName);
			}

			String xyzFilePath = input + ".xyz";
			String QFilePath = siteEvalDir + siteName + ".Q";
			command = plotShellPath + " " + xyzFilePath + " " + QFilePath;
			out = exec(command);
			if (out.length() > 0) {
				log("Results for plotting for " + siteName + ":" + out);
			} else {
				log("Sucessfully plotted for " + siteName);
			}

			lastEvalTimeMilli = System.currentTimeMillis();

			checkStateChange(input, QFilePath);
			recordStateChangeSummary();
		}

		protected void checkStateChange(String inputFilePath, String qFilePath) {
			try {
				String line1, line2, inputChange, input2;
				BufferedReader brQ = new BufferedReader(new FileReader(
						qFilePath));
				line1 = brQ.readLine();
				line2 = brQ.readLine();

				BufferedReader brInput = new BufferedReader(new FileReader(
						inputFilePath));
				input2 = brInput.readLine();
				input2 = brInput.readLine();

				inputChange = null;
				while (line2 != null) {
					if (!line1.equals(line2)) {
						inputChange = input2;
						publishData(makeResultMsg(line1, line2, input2)
								.getBytes());
					}
					line1 = line2;
					line2 = brQ.readLine();
					input2 = brInput.readLine();
				}
				brQ.close();
				brInput.close();

				if (inputChange != null) {
					System.out.println("line1 in checkStateChange:"
							+ inputChange);
					int tab1, tab2, tab3;
					tab1 = inputChange.indexOf('\t');
					tab2 = inputChange.indexOf('\t', tab1 + 1);
					tab3 = inputChange.indexOf('\t', tab2 + 1);
					Calendar changeTime = Calendar.getInstance();
					UtilSet.setDateByString(changeTime, inputChange.substring(
							tab1 + 1, tab2));
					String timeStr = inputChange.substring(tab2 + 1, tab3);
					System.out
							.println("timeStr in checkStateChange:" + timeStr);
					int colon1 = timeStr.indexOf(':');
					int colon2 = timeStr.indexOf(':', colon1 + 1);
					int posAMPM = timeStr.indexOf('M') - 1;
					changeTime.set(Calendar.HOUR, Integer.parseInt(timeStr
							.substring(0, colon1)));
					changeTime.set(Calendar.MINUTE, Integer.parseInt(timeStr
							.substring(colon1 + 1, colon2)));
					changeTime.set(Calendar.SECOND, Integer.parseInt(timeStr
							.substring(colon2 + 1, posAMPM)));
					if (timeStr.charAt(posAMPM) == 'A')
						changeTime.set(Calendar.AM_PM, Calendar.AM);
					else
						changeTime.set(Calendar.AM_PM, Calendar.PM);

					stateChangeTimes.add(changeTime);
					if (stateChangeTimes.size() > (86400000 / evalPeriodMilli))
						stateChangeTimes.remove();
					System.out.println("state change found for " + siteName
							+ " at " + getDateString(changeTime, true));
				} else {
					stateChangeTimes.add(null);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		protected String makeResultMsg(String oldStatus, String newStatus,
				String inputLine) {
			int tab1, tab2, tab3;
			tab1 = inputLine.indexOf('\t');
			tab2 = inputLine.indexOf('\t', tab1 + 1);
			tab3 = inputLine.indexOf('\t', tab2 + 1);

			String stationName = inputLine.substring(0, tab1).toLowerCase();

			Calendar changeTime = Calendar.getInstance();
			UtilSet.setDateByString(changeTime, inputLine.substring(tab1 + 1,
					tab2));
			String timeStr = inputLine.substring(tab2 + 1, tab3);
			System.out.println("timeStr in checkStateChange:" + timeStr);
			int colon1 = timeStr.indexOf(':');
			int colon2 = timeStr.indexOf(':', colon1 + 1);
			int posAMPM = timeStr.indexOf('M') - 1;
			int hour = Integer.parseInt(timeStr.substring(0, colon1));
			if (timeStr.charAt(posAMPM) == 'P' && hour < 12)
				hour += 12;
			changeTime.set(Calendar.HOUR_OF_DAY, hour);
			changeTime.set(Calendar.MINUTE, Integer.parseInt(timeStr.substring(
					colon1 + 1, colon2)));
			changeTime.set(Calendar.SECOND, Integer.parseInt(timeStr.substring(
					colon2 + 1, posAMPM)));

			return stationName + ';' + UtilSet.getDateTimeString(changeTime)
					+ ';' + oldStatus + "to" + newStatus + "\nEOF\n";
		}

		/**
		 * check if the station has changed its state recently within timeRange
		 * 
		 * @param timeRange
		 * @return
		 */
		public boolean isChangedInRecent(long timeRange) {
			Calendar now = Calendar.getInstance();
			for (int i = stateChangeTimes.size() - 1; i >= 0; i--) {
				Calendar changeTime = (Calendar) stateChangeTimes.get(i);
				if (changeTime != null) {
					if (now.getTimeInMillis() - changeTime.getTimeInMillis() <= timeRange)
						return true;
					else
						return false;
				}
			}

			return false;
		}

		protected void addHistData(String line) {
			Calendar now = Calendar.getInstance();
			if (calLastHistData == null
					|| fwHist == null
					|| now.get(Calendar.YEAR) > calLastHistData
							.get(Calendar.YEAR)
					|| now.get(Calendar.MONTH) > calLastHistData
							.get(Calendar.MONTH)
					|| now.get(Calendar.DAY_OF_MONTH) > calLastHistData
							.get(Calendar.DAY_OF_MONTH)) {
				try {
					if (fwHist != null) {
						fwHist.flush();
						fwHist.close();
					}
					String histFileDir = siteHistDir + now.get(Calendar.YEAR)
							+ File.separator + (now.get(Calendar.MONTH) + 1)
							+ File.separator;
					File fDir = new File(histFileDir);
					if (!fDir.exists())
						fDir.mkdirs();
					String histFilePath = histFileDir + siteName + "_"
							+ getDateString(now, false) + ".dat";
					fwHist = new FileWriter(histFilePath, true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			try {
				fwHist.write(line);
			} catch (Exception e) {
				e.printStackTrace();
			}
			calLastHistData = now;
		}

	}

	protected class messageProcessor extends Thread {

		public void run() {
			boolean running = true;
			try {
				while (running) {
					synchronized (listCV) {
						if (eventList.size() == 0) {
							listCV.wait();
						}
						NBEvent nbEvent = (NBEvent) eventList.remove(0);						
						byte[] resultBytes = nbEvent.getContentPayload();
						Results results = ResultsFactory.getInstance().getResults(resultBytes);
						byte[] data2 = results.getResultPayload();						
						if (data2 != null && data2.length > 0) {
							ResultPayload resultPayload = ResultPayload
									.getInstance();
							String dataStringArray[] = resultPayload
									.getStringArray(data2);
							processMessage(dataStringArray);
						}
					}
				}
				return;
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}

	}

	protected static Properties properties = null;
	protected static long dayMilli = 86400 * 1000;
	protected static long remodelPeriodMilli = -1;
	protected static long evalPeriodMilli = -1;
	protected static long modelDataTimeMilli = -1;
	protected static String dataDir = null;
	protected static String evalDir = null;
	protected static String histDir = null;
	protected static String rdahmmTrainShellPath = null;
	protected static String rdahmmEvalShellPath = null;
	protected static String plotShellPath = null;
	protected static boolean isHistSaved = false;
	protected static Calendar calNow = Calendar.getInstance();
	protected String networkName;

	protected messageProcessor msgProcessor;
	protected Hashtable pSitesTable;
	protected Hashtable aSitesTable;
	protected LinkedList eventList;
	protected Object listCV;
	protected ThreadPool modelThreadPool;

	public AsciiPosRdahmmRunner(String commType, String nbHost, String nbPort,
			String subTopic, String pubTopic, String networkName) {
		pSitesTable = new Hashtable();
		aSitesTable = new Hashtable();
		eventList = new LinkedList();
		listCV = new Object();
		this.networkName = networkName;
		loadProperties();

		String[] initArgs = { commType, nbHost, nbPort, subTopic, pubTopic };
		modelThreadPool = null;
		initialize(initArgs);
		msgProcessor = new messageProcessor();
		msgProcessor.start();
	}

	protected void loadProperties() {
		if (properties != null) {
			return;
		}

		try {
			properties = PropertyFile.loadProperties("sensorgrid.properties");
			evalDir = properties.getProperty("rdahmm.eval.directory");
			dataDir = properties.getProperty("rdahmm.data.directory");
			histDir = properties.getProperty("rdahmm.hist.directory");
			rdahmmTrainShellPath = properties
					.getProperty("rdahmm.trainshell.directory");
			rdahmmEvalShellPath = properties
					.getProperty("rdahmm.evalshell.directory");
			plotShellPath = properties
					.getProperty("rdahmm.plotshell.directory");
			remodelPeriodMilli = Long.parseLong(properties
					.getProperty("rdahmm.remodel.days"))
					* dayMilli;
			evalPeriodMilli = Long.parseLong(properties
					.getProperty("rdahmm.eval.minutes")) * 60000;
			modelDataTimeMilli = Long.parseLong(properties
					.getProperty("rdahmm.modeldata.hours")) * 60 * 60000;
			isHistSaved = Boolean.parseBoolean(properties
					.getProperty("rdahmm.save.hist"));
			log("[RdahmmFilter] --> Rdahmm Application Directory = " + evalDir);
			log("[RdahmmFilter] --> Rdahmm Data Directory = " + dataDir);
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (properties == null || evalDir == null || dataDir == null
				|| rdahmmTrainShellPath == null || rdahmmEvalShellPath == null
				|| plotShellPath == null || remodelPeriodMilli == -1
				|| evalPeriodMilli == -1) {
			System.err.println("Fatal Error: failed to load properties!");
			System.exit(-1);
		}
	}

	public void onEvent(NBEvent nbEvent) {
		if (nbEvent.getContentPayload() != null) {
			synchronized (listCV) {
				eventList.add(nbEvent);
				if (eventList.size() >= 1) {
					listCV.notify();
				}
			}
		}
	}

	public void processMessage(String[] msg) {
		try {
			StringTokenizer ast = new StringTokenizer(msg[0], "\n");
			while (ast.hasMoreTokens()) {
				String atoken = ast.nextToken();
				if (!atoken.startsWith("EOF")) {
					if (atoken.length() > 30) {
						String asiteName = atoken.substring(26, 30);
						if (aSitesTable.get(asiteName) != null) {
							AsciiRdahmmProcessor arp = (AsciiRdahmmProcessor) aSitesTable
									.get(asiteName);
							arp.addLine(atoken + "\n");
						} else {
							AsciiRdahmmProcessor arp = new AsciiRdahmmProcessor(
									asiteName, dataDir, evalDir, histDir);
							aSitesTable.put(asiteName, arp);
							arp.addLine(atoken + '\n');
						} // System.out.println("ASCII:/n" + atoken + "/n");
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		try {
			StringTokenizer pst = new StringTokenizer(msg[1], "\n");
			while (pst.hasMoreTokens()) {
				String ptoken = pst.nextToken();
				if (!ptoken.startsWith("EOF")) {
					if (ptoken.length() > 4) {
						String psiteName = ptoken.substring(0, 4);
						if (pSitesTable.get(psiteName) != null) {
							PosRdahmmProcessor prp = (PosRdahmmProcessor) pSitesTable
									.get(psiteName);
							prp.addLine(ptoken + "\n");
						} else {
							PosRdahmmProcessor prp = new PosRdahmmProcessor(
									psiteName, dataDir, evalDir, histDir);
							pSitesTable.put(psiteName, prp);
							prp.addLine(ptoken + '\n');
						} // System.out.println("POS:/n" + ptoken + "/n");
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * save the state change information of every station
	 */
	protected void recordStateChangeSummary() {
		try {
			synchronized (pSitesTable) {
				FileWriter fw = new FileWriter(evalDir + File.separator
						+ "state_change_" + networkName.toLowerCase() + ".txt",
						false);
				Enumeration e = pSitesTable.elements();
				while (e.hasMoreElements()) {
					PosRdahmmProcessor site = (PosRdahmmProcessor) e
							.nextElement();
					fw.write(site.getSiteName().toLowerCase());
					if (site.isChangedInRecent(7200000))
						fw.write(" yes");
					else
						fw.write(" no");

					if (site.isChangedInRecent(86400000))
						fw.write(" yes\n");
					else
						fw.write(" no\n");
				}
				fw.flush();
				fw.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Execute a command
	 * 
	 * @param execStr
	 *            String command string
	 * @return String the information of execute result
	 */
	public static String exec(String execStr) {
		Runtime runtime = Runtime.getRuntime();// Get current runtime object
		String outInfo = ""; // execute error information
		try {
			String osname = System.getProperty("os.name");
			String[] args = null;
			if (osname.equals("Linux")) {
				args = new String[] { "sh", "-c", execStr }; // execute
			} else if (osname.substring(0, 3).equals("Win")) {
				args = new String[] { "cmd", "/c", execStr }; // execute
			} else {
				System.exit(0);
			}

			Process proc = runtime.exec(args);
			InputStream out = proc.getInputStream();
			BufferedReader br1 = new BufferedReader(new InputStreamReader(out));
			while (br1.readLine() != null) {
			}
			out.close();

			InputStream in = proc.getErrorStream(); // get error information
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String line = "";
			while ((line = br.readLine()) != null) {
				outInfo = outInfo + line + "\n";
			}
			in.close();

			try { // check the result
				if (proc.waitFor() != 0) {
					System.err.println("exit value = " + proc.exitValue());
				}
			} catch (InterruptedException e) {
				System.err.print(e);
				e.printStackTrace();
			}

		} catch (IOException e) {
			System.out.println("exec error: " + e.getMessage());
			e.printStackTrace();
		}
		return outInfo;
	}

	public static String getDateString(Calendar date, boolean timeWanted) {
		StringBuffer ret = new StringBuffer();
		ret.append(date.get(Calendar.YEAR)).append('-').append(
				date.get(Calendar.MONTH) + 1);
		ret.append('-').append(date.get(Calendar.DAY_OF_MONTH));
		if (timeWanted) {
			ret.append(' ').append(date.get(Calendar.HOUR_OF_DAY)).append(':');
			ret.append(date.get(Calendar.MINUTE)).append(':').append(
					date.get(Calendar.SECOND));
		}
		return ret.toString();
	}

	public static void log(String str) {
		calNow.setTimeInMillis(System.currentTimeMillis());
		System.out.println('[' + getDateString(calNow, true) + "] " + str);
	}

	public static void copyFileToFile(File sourceFile, File destFile)
			throws Exception {
		InputStream in = new FileInputStream(sourceFile);
		OutputStream out = new FileOutputStream(destFile);
		byte[] buf = new byte[1024 * 16];
		int length;
		while ((length = in.read(buf)) > 0) {
			out.write(buf, 0, length);
		}
		in.close();
		out.flush();
		out.close();
	}

	protected class modelThread extends Thread {
		private int threadNum = 10;
		ThreadPool tPool;
		String trainShPath;
		String inputPath;
		double maxLValue = 0;

		public modelThread(String trainShPath, String inputPath,
				ThreadPool tPool) {
			this.trainShPath = trainShPath;
			this.inputPath = inputPath;
			this.tPool = tPool;
		}

		public void run() {
			if (tPool != null)
				modelMultipleOneTries();
			else
				modelDirectTenTries();
		}

		private void modelDirectTenTries() {
			log("starting to build model for " + inputPath);
			String res = exec(trainShPath + " " + inputPath + " 5 1234 10");
			if (res.length() == 0) {
				log("model successfully built");
			} else {
				log("results for building model for " + inputPath + ":");
				log(res);
			}
		}

		private void modelMultipleOneTries() {
			long st = System.currentTimeMillis();
			int idx = inputPath.lastIndexOf(File.separatorChar);
			String sourceDir = inputPath.substring(0, idx);
			String fileName = inputPath.substring(idx + 1);
			try {
				modelOneTry[] oneTryList = new modelOneTry[threadNum];
				Random random = new Random(1234);
				for (int i = 0; i < threadNum; i++) {
					String destDirStr = sourceDir + File.separatorChar + "tmp"
							+ i;
					File destDir = new File(destDirStr);
					destDir.mkdirs();
					String destPath = destDir + File.separator + fileName;
					copyFileToFile(new File(inputPath), new File(destPath));
					oneTryList[i] = new modelOneTry(trainShPath, destPath,
							random.nextInt(9999));
					tPool.assign(oneTryList[i]);
				}
				tPool.complete();

				maxLValue = oneTryList[0].getLValue();
				int idxMax = 0;
				for (int i = 1; i < threadNum; i++) {
					double v = oneTryList[i].getLValue();
					if (v > maxLValue) {
						maxLValue = v;
						idxMax = i;
					}
				}
				File tmpDir = new File(oneTryList[idxMax].getInputDir());
				File[] tmpFiles = tmpDir.listFiles();
				for (int i = 0; i < tmpFiles.length; i++) {
					String modelFilePath = sourceDir + File.separator
							+ tmpFiles[i].getName();
					copyFileToFile(tmpFiles[i], new File(modelFilePath));
				}

				for (int i = 0; i < oneTryList.length; i++) {
					tmpDir = new File(oneTryList[i].getInputDir());
					tmpFiles = tmpDir.listFiles();
					for (int j = 0; j < tmpFiles.length; j++)
						tmpFiles[j].delete();
					tmpDir.delete();
				}

				long et = System.currentTimeMillis();
				log("starting time:" + st + "; ending time:" + et
						+ "; interval:" + (et - st));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	protected class modelOneTry implements Runnable {
		protected String inputPath;
		protected String trainShPath;
		protected int randomSeed;

		public modelOneTry(String trainShPath, String inputPath, int randomSeed) {
			this.trainShPath = trainShPath;
			this.inputPath = inputPath;
			this.randomSeed = randomSeed;
		}

		public void run() {
			String res = exec(trainShPath + " " + inputPath + " 5 "
					+ randomSeed + " 1");
			if (res.length() == 0) {
				log("model successfully built for seed " + randomSeed);
			} else {
				log("results for building model for seed " + randomSeed + ":");
				log(res);
			}
		}

		public String getInputDir() {
			int idx = inputPath.lastIndexOf(File.separatorChar);
			if (idx < 0)
				return "";
			else
				return inputPath.substring(0, idx);
		}

		public double getLValue() {
			try {
				int idx = inputPath.lastIndexOf('.');
				String path = inputPath.substring(0, idx + 1) + "L";
				BufferedReader br = new BufferedReader(new FileReader(path));
				double ret = Double.parseDouble(br.readLine());
				br.close();
				return ret;
			} catch (Exception e) {
				e.printStackTrace();
				return 0;
			}
		}
	}

	public static void main(String[] args) {
		if (args.length < 6) {
			System.out.println("Usage: "
							+ "java cgl.sensorgrid.sopac.gps.filters.AsciiPosProcessor "
							+ "commType nbHost nbPort subTopic pubTopic networkName");
			System.exit(0);
		}

		String commType = args[0];
		String nbHost = args[1];
		String nbPort = args[2];
		String subTopic = args[3];
		String pubTopic = args[4];
		String networkName = args[5];
		AsciiPosRdahmmRunner test = new AsciiPosRdahmmRunner(commType, nbHost,
				nbPort, subTopic, pubTopic, networkName);
	}

}